home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Explosion 2
/
Software Explosion 2 - Virtual Computer Pets (1997).iso
/
blitz_data
/
gorny3dset
/
3dlibrary.doc
< prev
next >
Wrap
Text File
|
1997-08-29
|
20KB
|
601 lines
*********************************************
* *
* *
* 3D Graphics Library for Blitz Basic II *
* *
* *
* Version 0.9 Beta *
* *
* 2B3D (C) 1996 Maciej R. Gorny *
* *
*********************************************
CONTENT
1] HELLO
2] 3D COORDINATE SYSTEM
3] POLYGONS SUPPORTED
4] 3D COMMANDS
5] 3D WORLD LIMITS
6] DATA STRUCTURES AND NEWTYPES
7] PLG - 3D OBJECT FILE FORMAT
8] THINGS TO WATCH OUT FOR
9] CONTACTING AUTHOR
1] HELLO
_____________________________________________________________________________
My main goal was to have a set of functions (or statements) which would
allow me to create 3D programs, mainly I was thinking about games here, but not
only. Well, I run out of time to complete any particular program and this
set of functions is as far as I got. I haven't been able to test in on
machine other than mine, which is 68000 powered A2000 with 1.3 Workbench so
I don't think there should be any problems on other machines.
It is rather modest library. It does not support things like z-buffer, texture
mapping, or BSP. It simply reads objects in a format transforms between
different coordinate systems (object's local, world, and camera coordinates)
and projects the resulting image made up of polygons onto current screen.
It also performs backface culling to reduce number of polygons projected,
and either one (z) plane clipping or the entire viewing volume clipping
(frustum). It also shades the polygons in rather simple manner to give a bit
more depth and make it look better.
I did not use z-buffer here. I found that scan converting each polygon about to
be drawn and calculating z-axis values of each pixel in a polygon to be too
much to handle for my Amiga. Also, Blitz2 does not provide any easy way to
allocate global array from within a function so the only way I could think of
to implement z-buffer would be to DIM an array and provide only one z-buffer
size. Besides, z-buffer uses a lot of memory, so this is a task for later
updates of the library. The library uses a variant of so called painter's
algorythm to find out which polygons should be drawn first, and draws them
in back-to-front order. This solution may cause some problems if there are
many objects and very close to each other, but with careful planning those
problems can be avoided.
Once I get this version a bit more optimized, so performance is more acceptable,
I will add z-buffer functions, as well as better light sourcing functions.
For example right now it does not matter how far away is a light source located
from the objects. Also I will add Gouraud shading and maybe even texture
mapping if I get it to run at decent speeds.
The library is really slow at this stage. That's because this version is
not completely optimized yet, and most of all is written fully in Blitz2.
It contains no assembly code whatsoever, due to the fact that I don't know
anything about 68000 assembly. Some inner loops could probably benefit greatly
from some assembly, as could the entire library I suppose.
This is the beta release of the software library and as such may contain some
bugs. If you find any please do not hesitate to contact me and let me know:
Maciej Gorny
gorn4907@mars.rowan.edu
or: 424A Victoria Ave.
Glassboro, NJ 08028, USA
Some of the bugs were especially hard to figure out. RotateObject()
function for example takes four parameter. Three being the angles and
another serves as padding of some sort, without which last parameter
(z-axis angle) had been corrupted. I couldn't find a reason for that, I
just found the solution which makes RotateObject() work.
If you have any questions, please don't hesitate to send me email or write.
2] 3D COORDINATES SYSTEM
_____________________________________________________________________________
Coordinate system used is a left-handed coordinate system: X-axis goes from left
to right, Y-axis, from down up-wards, and Z-axis from behind (us) into the
screen.
^ +Y
| Into the screen
|
| +Z
| /
| /
| /
| /
| /
|/
-X ---------------------------> +X
/|
/ |
/ |
/ |
/ |
-Z/ |
|
Viewer | -Y
3] POLYGONS SUPPORTED
_____________________________________________________________________________
2B3D supports polygons with three vertices (triangles) and the ones with four
vertices (quads). All other will be either rejected or will cause problems.
Polygons can be one-sided or two-sided.
One-sided polygons will be visible only when they are facing a viewer. This is
useful if we want to limit number of polygons rendered to screen by using
backface culling and remove polygons that cannot be seen in an object. Objects
cannot concave in such case.
Two-sided polygons will always be rendered to a screen (provided they get
passed clipping procedures), because they have two sides that are visible to
a viewer: front and back.
4] 3D COMMANDS
_____________________________________________________________________________
Here's a list of commands in current version of 2B3D Library. A lot of them are
used internally by the system and end user will never have to use them, but I
included their descriptions anyway just so maybe someone will find them useful
somewhere else (like matrix multiplication, or vector math).
Display3D(w.l, h.l, d.l)
w = current screen width
h = current screen height
d = distance from viewer to projection plane
This must be called before any of the 3d functions can be used.
It precalculates some parameters needed by 3d engine and
establishes some default setting used bu the system (i.e. light
source, front and back clipping planes, etc...)
BuildLookUpTables()
Builds look up tables needed by the 3d system. This function is
automatically called by Display3D. Calling it again by a user
would be redundant and pointless.
AspectRatio{aspect.f}
aspect = an aspect ratio fraction
This function may be used to change screens aspect ration.
If a screen is 640x200 squares will look more like rectangles, and
circles like ovals. Best example of aspect ratio at work is to set
up your world the way you want it on a display with 1:1 aspect
ratio (or as close as possible) like 320x200 screen or 640x400.
Then change the display to something like 640x200 to see the effect.
I found aspect ratio=0.55 for 640x200 screen adequate and 1.55 for
screen 320x400.
Call this function to change the default aspect ratio (default=1).
MakeVector3D(a.vertex, b.vertex, r.vector)
Creates a vector (r) out of two vertices a and b.
VectorMag3D(v.vector)
Returns (float) a magnitude of a vector v.
DotProduct(u.vector, v.vector)
Returns (float) a dot product of two vectors.
CrossProduct(u.vector, v.vector, r.vector)
Finds a cross product of two vectors resulting in normal vector.
Normal vector is the one that is perpendicular to both vectors.
MatIdentity4x4(m.matrix4x4)
Initializes a matrix (m) to become an identity matrix.
MatZero4x4(m.matrix4x4)
Completely empties out a 4x4 matrix (sets it to 0s).
MatCopy4x4(s.matrix4x4, d.matrix4x4)
Copies a 4x4 source matrix (s) into a 4x4 destinatio matrix (d).
MatPrint4x4(m.matrix4x4)
Prints out content of a matrix (m) into output channel.
MatPrint1x4(m.matrix1x4)
Prints out content of a 1x4 matrix (m).
MatMult4x4(m.matrix4x4, n.matrix4x4, r.matri4x4)
Multiplies two 4x4 matrices together (m and n) and stores the result
in another 4x4 matrix (r).
MatMult4x4S{m.matrix4x4, n.matrix4x4, r.matrix4x4}
This is a special version of MatMult4x4 which is optimized for
multiplying matrices which contain rotation tranformations.
It is almost 50% faster than MatMult4x4().
MatMult1x4(a.matrix1x4, b.matrix4x4, r.matrix1x4)
Multiplies a 1x4 matrix (a) and 4x4 matrix (b) and stores the result
in a 1x4 matrix (r).
PLGGetLine(string.s)
Internal function. Used by PLG loader.
ComputeObjectRadius()
Internal function used by PLG loader.
PLGLoadObject(filename.s, scalar.f)
filename = file location on a disk.
scalar = scale factor
Loads a 3d object stored in a PLG like file format. An object may
be scaled as it is loaded by a scale factor. Set scale factor to 1,
if no scaling is desired.
Objects are loaded into a LIST type array, so most recently loaded
object becomes currently used object.
ObjectPrint()
Prints out all the information about currently used object.
TranslateObject(dx.l, dy.l, dz.l)
Moves currently used object into a new position in 3d world.
PositionObject(x.l, y.l, z.l)
Positions currently used object in a 3d world space. Should be called
right after an object is loaded, because by default loaded objects are
located at (0,0,0) world coordinates.
ScaleObject(s.f)
s = scale factor
Scales currently used object by scale factor.
if 0<s<1, object will shrink (0.5 is half the size)
if s=1, no change in object size
if s>1, object will be enlarged
RotateObject(rx,ry,pad,rz)
rx = degrees around X-axis
ry = degrees aroumd Y-axis
rz = degrees around Z-axis
pad= A dummy parameter to avoid Blitz2 corrupting rz parameter.
This is one of those bugs that I couldn't figure out. Seems
to work fine this way. I usually pass it as 0.
Rotates currently used object around X,Y, and Z (local) axis.
DrawTopTriangle(p1.pixel, p2.pixel, p3.pixel, color.w)
Draws a triangle with a flat top:
Serves as an internal function.
p1______p2
| /
| /
| /
| /
| / Points can be in any order.
| /
|/p3
DrawBottomTriangle(p1.pixel, p2.pixel, p3.pixel)
Draws a triangle with a flat bottom:
Serves as an internal function.
p1
|\
| \
| \ Points can be in any order
| \
| \
| \
p3|______p2
DrawTriangle2D{p1.pixel, p2.pixel, pad.w, p3.pixel)
Draws any triangle with vetices p1, p2, and p3 on a screen.
pad is necessary to prevent corruption of p3 values.
SetTriangleColor(color)
Sets a color used to draw triangles when using DrawTriangle2D function.
This parameter was supposed to be passed with the points when calling
the function, however, it kept corrupting the last point (p3).
\x and \y values received were different than the ones sent. This seems
to fix the problem.
ShowObjectWire()
Displays a wireframe representation of a currently used object
using perspective projection.
TouchPalette(first_reg, last_reg, init_color.rgbtype, final_color.rgbtype)
Creates a palette for use with shading functions. Actually, it alters
existing current screen's palette. It will affect current palette's
registers between first_reg and last_reg, and it will interpolate
color values from init_color to final_color.
ex.: I used a 16 color screen (registers 0-15). I wanted to have a
palette of 16 shades of gray where register 0 contains black,
and register 15 white color. To achieve this, we should use:
c1.rgbtype\r=0,0,0:c2.rgbtype\r=15,15,15:TouchPalette(0,15,c1,c2)
We also should make sure that objects which use that palette will
have color field specified to be 0 since shading is added as a
off of main color.
If we used 32 color screen we could use shades of two colors, i.e.
shades of grey and red. Registers 0-15 would contain shades of grey,
and registers 16-31. 16 being deep dark red, and 31 white or very
bright red. Our polygons could have two colors then: 0 and 16
specified in the polygon color field.
RemoveBackfacesAndShade()
Removes backfaces (invisible polygons with their back to viewer) and
calculates shade of their color. Uses current object.
DrawObjectSolid()
Same a ShowObjectWire(), but renders currently used object in its
solid form.
LocalToWorld()
Translates currently used object's local coordinates to world (global)
coordinates. Must be used everytime objects position has changed.
WorldToCamera()
Translates currently used object's word coordinates to camera viewing
coordinates. Must be called every time viewer's position changes or
object's position changes.
Used internally.
CreateWorldToCamera()
Creates a global, inverse transformation matrix used to transform world
coordinates to camera coordinates.
Used internally.
RemoveObject()
Returns TRUE if currently used object is within viewing volume, FALSE
otherwise.
DeleteObject()
Removes currently used object from 3d world system.
ClipMode(mode)
Sets the clipping mode for use by the system.
If mode==#FRUSTUM objects will be clipped against the entire
clipping volume.
If mode==#ZPLANE objects will be clipped only against a
specified plane on Z axis. This plane is specified in
Frustum() function as 'near' parameter.
Frustum(near, far)
Defines front and back clipping planes of the viewing volume on a Z
axis.
CreateLightSource(x,y,z)
Creates a vector describing direction from which rays of light from
infinite light source are coming. This is very primitive light sourcing
and the distance of a light source away from the objects has no effect
on their shading.
PositionCamera(x,y,z)
Places viewer (camera) in a 3d world at specified coordinates.
ViewAngle(angx, angy, angz)
Spefies angle at which a viewer is looking at the 3d world.
If all angles are 0, viewer is looking straight ahead down
the positive direction of Z-axis.
ClipObject3D()
Clips currently used object against viewing volume.
GeneratePolyList()
Creates a list of all polygons used in one frame. Must be called before
using any of the special invisible surface removing fuctions. Also
must be called whenever objects were added or removed from the 3d world.
Used internally.
PaintFrame()
Generates a view as seen from viewer's current position. This function
uses simple implementation of a popular Painter's algorythm to show
objects in correct order. The function sorts polygons according to their
maximum z values.
Polygons and objects should not be allowed to intersect each other.
That's where shortcomings of that algorythm become visible, but
nevertheless creates some interesting effects I think.
NewView()
Recalculates scenery and prepares it for display using PaintFrame().
This function should be called every time a scene has changed (i.e.
viewpoint has been moved, or viewing angle changed, or maybe a new
object entered a scene).
MoveForward(dist)
Moves a viewer forward by 'dist' units (duh!). To move back simply
enter negative value for dist.
MoveUp(dist)
Relocates a viewer up the Y axis.
MoveDown(dist)
Moves a viewer down the Y axis.
ObjectsUseColor(reg)
Forces all objects in the 3d world to use 'reg' as the base for the
shading offset. Using TouchPalette() it is possible to specify only
part of any palette to hold shade variations of some color, and
using ObjectsUseColor() will force all objects to use our new base
and the offsets overriding whatever color field was specified in
object's PLG file.
Example of using it and palette manipulation is in DEMO2.BB2
CameraX(), CameraY(), CameraZ()
All functions return their relevant position in the 3d world.
They return long word (.l)
AngleX(), AngleY(), AngleZ()
These functions return cameras viewing angles. They return long
value (.l)
5] 3D WORLD LIMITS
_____________________________________________________________________________
There are some limits involved such as how many vertices one polygon is
allowed to have, how many polygons are allowed in an object. Here is
the list:
MAXIMUM LIMIT
------------------------------------
vertices per polygon 4
polygons per object 32
vertices per object 128
objects in 3D world 32
polygons per frame 1024
------------------------------------
That last limit came about as a result of maximum objects allowed in a 3d
world and how many polygons there is allowed at most for each one of those
polygons. Of course the more polygons and objects we have to process each
frame, the slower the whole thing will get.
6] DATA STRUCTURES AND NEWTYPES
_____________________________________________________________________________
Please look at DATASTRUCTS.DOC file for listing of NEWTYPE structures and
other relevant information.
7] PLG OBJECT FILE FORMAT
_____________________________________________________________________________
This file format is easy enough to understand so anyone can design their own
objects and write them into a PLG file manually. This library does not support
PLG files fully, because color information is handled here differently. Other
than that everything is pretty much as in standard PLG files.
Format is very simple. It contains a list of vertices that comprise an object
and a list of polygons as well. The first line is a header and contains
the name of an object followed by number of vertices and number of polygons.
A list of all vertices follows next. Vertices must be presented in x, y, z
form, with at least one space between each vertex. One vertex per line is
allowed.
After that a list of polygons follows. One polygon per line is allowed. The
first number is the color, then number of vertices in this polygon follows,
followed by list of vertices that compose that polygon.
In real PLG file color information could be decimal or hexadecimal number, but
this library can read only decimal numbers and that number contains no other
information other than which register it is in a palette, whatever RGB value
that may be. So there is no actual RGB value stored there, or shading, or
special effect information like it would be in an actual PLG file. But that's
all this library needs. If you would like indicate that a particular polygon
should be a double sided polygon (that is it will be rendered regardless if
it is with its front or back to viewer), you only need to add 4096 to the
color register value. It will set the first bit of the last 4-bit nibble to
one. The last four bits are supposed to contain additional information about
a polygon, like special sahding, coloring, effects, etc... Currently 2B3D can
only read if a polygon is onesided or two sided from that field.
Comments may be placed anywhere in a file. Anything followed by a '#' (number
sign) or ';' (semicolon) until the end of the line is considered a comment
and will be ignored by PLG reader.
Look up some .plg files that were included in this archive for examples of the
format.
8] THINGS TO WATCH OUT FOR
_____________________________________________________________________________
Constant shading is not really supported yet. Objects are expected to use
flat shading when they are loaded from a .plg file.
Also, the entire objects and polygons get cut from the view if they cross
clipping planes. Dividing polygons would create polys with more than four
vertices (which is not supported here) and would further slow down the
whole thing.
9] CONTACTING AUTHOR
_____________________________________________________________________________
And that is it. This is my little attempt at having written a 3D game in
Blitz2 and this is as far as I got. Hopefully in the near future I will be
able to do some more work on this library and expand it further.
If you have any questions, comments, or wish to contact me, send me email at
gorn4907@mars.rowan.edu or send mail to Maciej Gorny, 424A Victoria Ave.,
Glassboro, NJ, 08028, USA. I hope you have as much fun using it as I had
writing it. Take care!
Maciej Gorny
gorn4907@mars.rowan.edu
424A Victoria Avenue
Glassboro, NJ 08028
USA
__________________________________________________________________________
| |
| BlitzBasic II 3D Graphics Library. Copyright (C) 1996 Maciej R. Gorny. |
|__________________________________________________________________________|